package main

import (
	"fmt"
	"sync"
	"time"
)

var syncWait sync.WaitGroup

// 向intChan中放入1-400000个数
func putNum(num int, intChan chan<- int) {
	for i := 2; i <= num; i++ {
		intChan <- i
	}
	close(intChan)
	syncWait.Done()
}

// 从intChan取出数据,并判断是否为素数放入primeChan中
func primeNum(intChan <-chan int, primeChan chan<- int, exitChan chan<- bool) {
	for num := range intChan {
		flag := true
		for i := 2; i < int(num/2)+1; i++ {
			if num%i == 0 {
				flag = false
				break
			}
		}
		if flag {
			primeChan <- num // num是素数
		}
	}
	exitChan <- true
	syncWait.Done()
}

func printPrime(primeChan <-chan int) {
	// count := 0
	// for num := range primeChan {
	// 	fmt.Printf("数字: %v是素数\n", num)
	// 	count++
	// }
	// fmt.Printf("一共有%v个素数\n", count)
	syncWait.Done()
}

func main() {
	start := time.Now()
	cpuNum := 14
	num := 400000
	intChan := make(chan int, num/8)
	primeChan := make(chan int, num/8)
	exitChan := make(chan bool, cpuNum) // 标识子线程运行结束,可以关闭管道

	// 存放数字的协程
	syncWait.Add(1)
	go putNum(num, intChan)

	// 统计素数的协程
	for i := 0; i < cpuNum; i++ {
		syncWait.Add(1)
		go primeNum(intChan, primeChan, exitChan)
	}
	// 打印素数的协程
	syncWait.Add(1)
	go printPrime(primeChan)

	// 关闭管道
	syncWait.Add(1)
	go func() {
		for i := 0; i < cpuNum; i++ {
			<-exitChan
		}
		close(primeChan) // 关闭管道
		syncWait.Done()
	}()

	syncWait.Wait()
	timer := time.Since(start)
	fmt.Printf("程序执行时间: %v 秒", timer)
}
